﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Web.Mvc;
using System.Web.Routing;

namespace Gama.Extension
{
    public static class ControllerExtensions
    {
        public const string ControllerNameSuffix = "Controller";

        internal static string GetControllerName<TController>()
            where TController : IController
        {
            string controllerName = typeof(TController).Name;

            if (controllerName.EndsWith(ControllerNameSuffix, StringComparison.OrdinalIgnoreCase))
            {
                controllerName = controllerName.Substring(0, controllerName.Length - ControllerNameSuffix.Length);
            }

            return controllerName;
        }

        internal static RouteValueDictionary CreateRoutes<TController>(MethodCallExpression call)
            where TController : Controller
        {
            RouteValueDictionary routes = new RouteValueDictionary();

            routes["controller"] = GetControllerName<TController>();
            routes["action"] = call.Method.Name;

            ParameterInfo[] parameters = call.Method.GetParameters();

            if (parameters.Length > 0)
            {
                for (int i = 0; i < parameters.Length; i++)
                {
                    Expression argument = call.Arguments[i];                    

                    object argumentValue = Expression.Lambda(argument).Compile().DynamicInvoke();

                    routes.Add(parameters[i].Name, argumentValue);
                }
            }

            return routes;
        }

        public static RouteValueDictionary CreateRoutes<TController>(Expression<Func<TController, ActionResult>> expression)
            where TController : Controller
        {
            MethodCallExpression body = expression.Body as MethodCallExpression;

            return CreateRoutes<TController>(body);
        }

        public static RedirectToRouteResult RedirectToAction<TController>(this Controller controller, Expression<Func<TController, ActionResult>> expression)
            where TController : Controller
        {
            return new RedirectToRouteResult(CreateRoutes(expression));
        }

        public static RedirectToRouteResult RedirectToAction<TController>(this TController controller, Expression<Func<TController, ActionResult>> expression)
            where TController : Controller
        {
            return RedirectToAction((Controller) controller, expression);
        }

        public static TransferResult TransferToRoute(this Controller controller, RouteValueDictionary routeValues)
        {
            return new TransferResult(routeValues, controller.RouteData);
        }

        public static TransferResult TransferToRoute(this Controller controller, object routeValues)
        {
            return new TransferResult(routeValues, controller.RouteData);
        }

        public static TransferResult TransferToAction<TController>(this Controller controller, Expression<Func<TController, ActionResult>> expression)
            where TController : Controller
        {
            return new TransferResult(CreateRoutes(expression), controller.RouteData);
        }
    }
}
